package engine

import (
	"awesomeProject2/db"
	m "awesomeProject2/model"
	rutil "awesomeProject2/redis"
	"fmt"
	gredis "github.com/redis/go-redis/v9"
	"gorm.io/gorm"
	"log"
	"sync"
	"time"
)

type MatchEngine struct {
	mu        sync.Mutex
	rdb       *gredis.Client
	OrderBook *OrderBook
}

func NewEngine(rdb *gredis.Client) *MatchEngine {
	return &MatchEngine{
		rdb:       rdb,
		OrderBook: &OrderBook{},
	}
}

func (me *MatchEngine) MatchDistributed(token string) {
	lockKey := fmt.Sprintf("lock:order:%s", token)
	ok, val := rutil.AcquireLock(me.rdb, lockKey, 2*time.Second)
	if !ok {
		return
	}
	defer rutil.ReleaseLock(me.rdb, lockKey, val)

	me.mu.Lock()
	defer me.mu.Unlock()

	me.OrderBook.Sort()
	me.matchOrders(token)
}

func (me *MatchEngine) matchOrders(token string) {
	for _, buy := range me.OrderBook.BuyOrders {
		if buy.Remain <= 0 {
			continue
		}
		for _, sell := range me.OrderBook.SellOrders {
			if sell.Remain <= 0 {
				continue
			}
			if buy.Price >= sell.Price {
				amount := min(buy.Remain, sell.Remain)
				price := sell.Price
				err := me.tradeTx(buy, sell, amount, price)
				if err != nil {
					fmt.Println("交易失败", err)
					continue
				}
				buy.Remain -= amount
				sell.Remain -= amount
			}
		}
	}
}

func (me *MatchEngine) tradeTx(buy, sell *m.Order, amount, price float64) error {
	return db.DB.Transaction(func(tx *gorm.DB) error {
		// 1. 更新买单、卖单剩余数量
		buy.Remain -= amount
		sell.Remain -= amount
		if buy.Remain <= 0 {
			buy.Status = "FILLED"
		}
		if sell.Remain <= 0 {
			sell.Status = "FILLED"
		}

		// 2. 保存订单状态
		if err := tx.Save(buy).Error; err != nil {
			return err
		}
		if err := tx.Save(sell).Error; err != nil {
			return err
		}

		// 3. 插入成交记录
		trade := &m.Trade{
			BuyOrderID:  buy.ID,
			SellOrderID: sell.ID,
			Token:       buy.Token,
			Price:       price,
			Amount:      amount,
			Timestamp:   time.Now().Unix(),
		}
		if err := tx.Create(trade).Error; err != nil {
			return err
		}

		log.Printf("✅ 成交: 买单=%d 卖单=%d 数量=%.4f 价格=%.2f", buy.ID, sell.ID, amount, price)
		return nil // 返回 nil 表示提交事务
	})
}
